package DataModel.LayoutParser;

import java.awt.Point;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.LinkedList;

import DataModel.CommonLibrary.CommonDefs.Layer;
import DataModel.LayoutManager.CPolygon;
import DataModel.LayoutManager.CRectangle;

/**
 * Class to export layout data structure to CIF format
 * 
 * @author evgeni
 *
 */
public class CIFExporter
{
	/***************************************************/
	/****** Members ************************************/
	/***************************************************/	
	private PrintWriter m_printWriter;


	/***************************************************/
	/****** C'tors *************************************/
	/***************************************************/
	CIFExporter()
	{}


	/***************************************************/
	/****** Public methods *****************************/
	/***************************************************/
	/**
	 * Layout export manager
	 * @param recsList - list of rectangles
	 * @param filePath - target path for export 
	 * @return false on success
	 */
	public static boolean Export(LinkedList<CRectangle> recsList, String filePath)
	{
		CIFExporter cifExporter = new CIFExporter();
		
		if(cifExporter.OpenOutputStream(filePath))
			return true;
		
		if(cifExporter.WriteLayout(recsList))
			return true;
		
		cifExporter.CloseOutputStream();
		
		return false;
	}
	
	/**
	 * Open output stream
	 * @param filePath - target file path
	 * @return false on success
	 */
	public boolean OpenOutputStream(String filePath)
	{
		try
		{
			// open output stream
        	m_printWriter = new PrintWriter(new BufferedWriter(new FileWriter(filePath)));
        } 
        catch (IOException e)
		{
            System.out.println("Error opening " + filePath+": "+e.getMessage());
            return true;
        }
        
        return false;
	}
	
	/**
	 * Close output stream
	 */
	public void CloseOutputStream()
	{
		m_printWriter.close();
	}
	
	/**
	 * Write layout to output stream
	 * @param recsList - list of rectangles
	 * @return false on success
	 */
	public boolean WriteLayout(LinkedList<CRectangle> recsList)
	{
		HashMap<Layer, LinkedList<CRectangle>> recsByLayer = new HashMap<Layer, LinkedList<CRectangle>>();

		// init recs by layer hash
		for (Layer layer : Layer.values()) 
			recsByLayer.put(layer, new LinkedList<CRectangle>());

		// sort recs list
		for (CRectangle rectangle : recsList) 
			recsByLayer.get(rectangle.getLayer()).add(rectangle);
		
		// print all layers and recs to output stream
		for (Layer layer : Layer.values()) 
		{
			if(recsByLayer.get(layer).size() == 0)
				continue;
			
			writeLayer(layer);
			
			for (CRectangle rectangle : recsByLayer.get(layer)) 
				writeRectangle(rectangle);
		}
		
		writeLine("E");
		
		return false;
	}

	
	/***************************************************/
	/****** Utils **************************************/
	/***************************************************/

	/**
	 * Write layer to output stream
	 * @param layer - layer enumeration
	 * @return false on success and true invalid layer
	 */
	private boolean writeLayer(Layer layer)
	{
		String layName = layer.toString();
		if (layName == null || layName.equals("")) 
			return true;
		
		writeLine("L " + layName + ";");
		
		return false;
	}

	/**
	 * Write rectangle to output stream
	 * 
	 * @param rec - rectangle to print
	 * @return false on success
	 */
	private boolean writeRectangle(CRectangle rec)
	{
		writeLine("B " +  rec.getLength() + " " + rec.getWidth() + " " + rec.getCenter().x + " " + rec.getCenter().y + ";");
		
		return false;
	}
	
	/**
	 * Write polygon to output stream
	 * 
	 * @param poly - polygon to print
	 * @return false on success
	 */
	private boolean writePolygon(CPolygon poly)
	{
		StringBuffer polyLine = new StringBuffer("P ");
		
		for (Point point : poly.getPointsList()) 
			polyLine.append(point.x + " " + point.y + " ");
		
		polyLine.append(";");
		
		writeLine(polyLine.toString());
		
		return false;
	}


	/**
	 * Write a line to output stream
	 * 
	 * @param line - string to print
	 * @return false on success
	 */
	private boolean writeLine(String line)
	{
		line = line + '\n';
		m_printWriter.print(line);
		
		return false;
	}
}
